﻿Imports System.Net
Imports System.Net.Sockets
Imports System.Text
Imports System.Threading
Imports System.Windows

Namespace TweeVo
	Public NotInheritable Class TiVoBeaconListener
		Public Shared Event TiVoFound As EventHandler(Of TiVoFoundEventArgs)

		Private Shared _thread As Thread
		Private Shared _listener As UdpClient

		Private Sub New()
		End Sub
		Public Shared Sub Start()
			' start a new thread
			If _thread Is Nothing Then
				_thread = New Thread(AddressOf DiscoverTiVos)
				_thread.IsBackground = True
				_thread.Start()
			End If
		End Sub

		Public Shared Sub [Stop]()
			_listener.Close()
		End Sub

		Private Shared Sub DiscoverTiVos()
			Dim dr As MessageBoxResult = MessageBoxResult.None

			Do
				Try
					' bind to port 2190
					_listener = New UdpClient(2190)
				Catch ex As SocketException
					' this error indicates something else is listening on the port, most likely TiVo Desktop
					If ex.ErrorCode = 10048 Then
						dr = MessageBox.Show("There is an application running already listening for TiVo beacons.  This means you're likely running TiVo Desktop on this computer.  If the TiVo list has not yet been loaded, please disable TiVo Desktop.  Once the list is filled in and settings are saved, TiVo Desktop can be restarted.  Try again?", "Error", MessageBoxButton.YesNo, MessageBoxImage.Exclamation)
						If dr = MessageBoxResult.No Then
							Return
						End If
					Else
						Throw
					End If
				End Try
			Loop While dr = MessageBoxResult.Yes

			' receive data from any IP on this port
			Dim ep As New IPEndPoint(IPAddress.Any, 2190)

			Do While _listener IsNot Nothing
				' get a beacon packet
				Dim bytes() As Byte = _listener.Receive(ep)
				Dim beacon As String = Encoding.ASCII.GetString(bytes)

				' parse it out
				Dim t As TiVo = ParseBeacon(beacon)
				' assign the IP of the incoming data (that's the TiVo's IP)
				t.IpAddress = ep.Address

				' if it's a new TiVo, add it to the hashtable
				If (TweeVoSettings.Default.TiVos Is Nothing OrElse (Not TweeVoSettings.Default.TiVos.ContainsKey(t.Identity))) AndAlso (Not t.Platform.StartsWith("pc")) Then
					If TweeVoSettings.Default.TiVos Is Nothing Then
						TweeVoSettings.Default.TiVos = New Dictionary(Of String,TiVo)()
					End If

					t.Active = True
					t.LastPolled = Date.Now
					TweeVoSettings.Default.TiVos(t.Identity) = t

					' raise the event to whoever is listening
					If TiVoFoundEvent IsNot Nothing Then
						Dim args As TiVoFoundEventArgs = New TiVoFoundEventArgs With {.TiVo = t}
						RaiseEvent TiVoFound(Nothing, args)
					End If
				End If
			Loop
		End Sub

		Private Shared Function ParseBeacon(ByVal beacon As String) As TiVo
			Dim t As New TiVo()

			' parse the beacon packet into properties
			Dim lines() As String = beacon.Split(ControlChars.Lf)
			For Each line As String In lines
				' parse the name/value pairs
				Dim values() As String = line.Split("="c)
				Select Case values(0).ToUpperInvariant()
					Case "PLATFORM"
						t.Platform = values(1)
					Case "MACHINE"
						t.Machine = values(1)
					Case "IDENTITY"
						t.Identity = values(1)
				End Select
			Next line

			Return t
		End Function
	End Class

	Public Class TiVoFoundEventArgs
		Inherits EventArgs
		Public TiVo As TiVo
	End Class
End Namespace
